home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-06-24 | 32.1 KB | 1,304 lines | [TEXT/MMCC] |
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Portions copyright © 1995 Mark D. Gerl. All rights reserved worldwide.
- //
- // Project: ProcessBar™
- //
- // File: mdg.c
- //
- // Description: Most of the code written to extend Matt Slot's appe Windows into what it is
- //
- // Written by: Mark D. Gerl
- //
- // Disclaimer: Written over 40 hours at MacHack '95 -- use at your own risk (actually, I think
- // this code is REALLY stable)!
- //
- ////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
- // Universal headers includes
- #include <Icons.h>
- #include <LowMem.h>
- #include <QDOffscreen.h>
-
- // Project-specific includes
- #include "Layers.h"
- #include "ScriptableFinder.h"
- #include "mdg.h"
-
-
- // Constants
-
- const RGBColor kBgGrayColor = { kTaskbarBgColor, kTaskbarBgColor, kTaskbarBgColor };
- const RGBColor kLtGrayColor = { kLtGrayColorValue, kLtGrayColorValue, kLtGrayColorValue };
- const RGBColor kDkGrayColor = { kDkGrayColorValue, kDkGrayColorValue, kDkGrayColorValue };
-
-
- // Externally visible variables
-
- WindowPtr gTaskbarWindow = (WindowPtr)0L;
- Boolean gTaskbarVisible = FALSE;
-
-
- // Local statics
-
- static Rect kMacOSIconRect = { kTaskbarTopMargin, kTaskbarLeftMargin,
- kStandardIconSize+kTaskbarTopMargin,
- kStandardIconSize+kTaskbarLeftMargin };
-
- static short gTaskbarNextPosition = kTaskbarLeftMargin + kStandardIconSize + kTaskbarButtonBorderSize + kTaskbarBetweenMargin;
-
- static PSNRec gPSNInfoArray[kMaxProcesses];
- static short gPSNInfoItemsCount = 0;
- static Rect gCurrentlyHilitedButtonRect = {0, 0, 0, 0};
-
- static GWorldPtr gBufferWorld = (GWorldPtr)0L;
-
-
- //--------------------------------------------------------------------------------------------------
- // Functions (not in any particular order)
- //--------------------------------------------------------------------------------------------------
-
- void SetupOffscreenWorld(void)
- {
- OSErr err;
- Rect bounds;
-
- // if the offscreen world doesn't exist, make it
- if (gBufferWorld == (GWorldPtr)0L)
- {
- // quick sanity check
- if (gTaskbarWindow == (WindowPtr)0L) return;
-
- // create a new offscreen world
- bounds = gTaskbarWindow->portRect;
- OffsetRect(&bounds, 0 - bounds.left, 0 - bounds.top);
- err = NewGWorld(&gBufferWorld, 0, &bounds, (CTabHandle)0L, (GDHandle)0L, useTempMem);
-
- // check to see if it was allocated; if not, try again without using temp mem
- if (gBufferWorld == (GWorldPtr)0L)
- err = NewGWorld(&gBufferWorld, 0, &bounds, (CTabHandle)0L, (GDHandle)0L, (GWorldFlags)0);
- }
- }
-
-
- void UpdateFromOffscreenWorld(Rect *r)
- {
- PixMapHandle pm;
-
- // if the offscreen world doesn't exist, try to create it
- if (gBufferWorld == (GWorldPtr)0L)
- {
- SetupOffscreenWorld();
- if (gBufferWorld == (GWorldPtr)0L)
- return;
- }
-
- pm = GetGWorldPixMap(gBufferWorld);
- if (LockPixels(pm))
- {
- // update from the desired rect (in local coordinates)
- ForeColor(blackColor);
- BackColor(whiteColor);
- CopyBits((BitMap*)(*pm), (BitMap*)&(qd.thePort->portBits), r, r, srcCopy, (RgnHandle)0L);
-
- UnlockPixels(pm);
- }
- }
-
-
- void Draw3DFrame(Rect * frame, FrameType ft)
- {
- Rect r = *frame;
- InsetRect(&r, -(kTaskbarButtonFrameWidth), -(kTaskbarButtonFrameWidth));
-
- PenSize(1, 1);
-
- if (ft == kFrameInset)
- {
- // RGBForeColor(&kDkGrayColor);
- ForeColor(blackColor);
- MoveTo(r.left, r.bottom-1);
- LineTo(r.left, r.top);
- LineTo(r.right-2, r.top);
- MoveTo(r.left+1, r.bottom-2);
- LineTo(r.left+1, r.top+1);
- LineTo(r.right-3, r.top+1);
- // RGBForeColor(&kLtGrayColor);
- ForeColor(whiteColor);
- MoveTo(r.right-1, r.top);
- LineTo(r.right-1, r.bottom-1);
- LineTo(r.left+1, r.bottom-1);
- MoveTo(r.right-2, r.top+1);
- LineTo(r.right-2, r.bottom-2);
- LineTo(r.left+2, r.bottom-2);
- }
- else if (ft == kFrameOutset)
- {
- // RGBForeColor(&kLtGrayColor);
- ForeColor(whiteColor);
- MoveTo(r.left, r.bottom-1);
- LineTo(r.left, r.top);
- LineTo(r.right-2, r.top);
- MoveTo(r.left+1, r.bottom-2);
- LineTo(r.left+1, r.top+1);
- LineTo(r.right-3, r.top+1);
- // RGBForeColor(&kDkGrayColor);
- ForeColor(blackColor);
- MoveTo(r.right-1, r.top);
- LineTo(r.right-1, r.bottom-1);
- LineTo(r.left+1, r.bottom-1);
- MoveTo(r.right-2, r.top+1);
- LineTo(r.right-2, r.bottom-2);
- LineTo(r.left+2, r.bottom-2);
- }
- else
- {
- DebugStr("\pDraw3DFrame- illegal frame type passed");
- }
-
- BackColor(whiteColor);
- ForeColor(blackColor);
- }
-
-
- void ShowTaskbar(WindowPtr win)
- {
- if ((win != (WindowPtr)0L) && !gTaskbarVisible)
- {
- short i;
- for (i = 1 + kTaskbarScreenBottomMargin; i <= kTaskbarHeight + 1; i += 4)
- {
- MoveWindow(win, qd.screenBits.bounds.left, qd.screenBits.bounds.bottom - i, FALSE);
- DrawTaskbar(win);
- SystemTask();
- }
- gTaskbarVisible = TRUE;
- }
- }
-
-
- void HideTaskbar(WindowPtr win)
- {
- if ((win != (WindowPtr)0L) && gTaskbarVisible)
- {
- short i;
- for (i = 1; i <= kTaskbarHeight - kTaskbarScreenBottomMargin + 1; i += 4)
- {
- MoveWindow(win, qd.screenBits.bounds.left, qd.screenBits.bounds.bottom-kTaskbarHeight + i, FALSE);
- DrawTaskbar(win);
- SystemTask();
- }
- gTaskbarVisible = FALSE;
- }
- }
-
-
- void ToggleTaskbarVisibility(WindowPtr win)
- {
- if (gTaskbarVisible == TRUE)
- HideTaskbar(win);
- else
- ShowTaskbar(win);
- }
-
-
- Boolean FindFirstVisibleProcess(ProcessSerialNumber *psn)
- {
- ProcessSerialNumber newPSN, curPSN;
- ProcessInfoRec psInfo;
- LayerPtr lp;
- OSErr err;
- Boolean result = FALSE, same;
-
- err = GetCurrentProcess(&curPSN);
-
- // loop over the processes looking for a visible process (that's not current or psn)
- newPSN.highLongOfPSN = newPSN.lowLongOfPSN = kNoProcess;
- do
- {
- err = GetNextProcess(&newPSN);
- if (err != noErr) break;
-
- // get the process information
- psInfo.processInfoLength = sizeof(ProcessInfoRec);
- psInfo.processName = 0L;
- psInfo.processAppSpec = 0L;
- err = GetProcessInformation(&newPSN, &psInfo);
- if (err != noErr)
- {
- // DebugStr("\pFindFirstVisibleProcess- GetProcessInformation() failed;g");
- break;
- }
- else if (psInfo.processMode & modeOnlyBackground)
- continue;
-
- // ignore this process if it's our process
- err = SameProcess(&curPSN, &newPSN, &same);
- if (same == TRUE)
- continue;
-
- // ignore this process if it's the same as the one being hidden
- err = SameProcess(psn, &newPSN, &same);
- if (same == TRUE)
- continue;
-
- lp = ProcessLayer(&newPSN);
- if (HiddenLayer(lp))
- {
- *psn = newPSN;
- result = TRUE;
- break;
- }
-
- } while (err == noErr);
-
- return result;
- }
-
-
- void TogglePSNVisibility(ProcessSerialNumber *psn)
- {
- ProcessSerialNumber frontPSN;
- OSErr err;
- Boolean result;
- short index;
-
- LayerPtr lp = ProcessLayer(psn);
-
- // if visible, then we're trying to hide it...
- if (HiddenLayer(lp))
- {
- // check to see if we're trying to hide the current front process
- err = GetFrontProcess(&frontPSN);
- err = SameProcess(psn, &frontPSN, &result);
- // if yes, make sure there is another non-hidden process to go to...
- if (result == TRUE)
- {
- if (FindFirstVisibleProcess(&frontPSN))
- {
- err = SetFrontProcess(&frontPSN);
- ShowHideLayer(lp, FALSE);
- }
- // else, sysbeep, because we cannot hide the last visible process
- else
- SysBeep(1);
- }
- else
- ShowHideLayer(lp, !HiddenLayer(lp));
- }
- else
- ShowHideLayer(lp, !HiddenLayer(lp));
-
- // update the icon for this process
- if (FindPSNInProcessArray(psn, &index))
- {
- LayerPtr lp = ProcessLayer(psn);
- Rect temp = gPSNInfoArray[index].buttonRect;
-
- temp.right = temp.left + kStandardIconSize;
- err = PlotIconSuite(&temp, atLeft, HiddenLayer(lp) ? ttNone : ttDisabled, gPSNInfoArray[index].iconSuite);
- }
- }
-
-
- void BringPSNToFront(ProcessSerialNumber *psn)
- {
- short index;
-
- UpdateProcessArray();
-
- if (FindPSNInProcessArray(psn, &index))
- SetFrontProcess(psn);
- }
-
-
- void Remove1TaskbarProcess(short processArrayIndex)
- {
- RgnHandle savedClip;
- GrafPtr savedPort;
- Rect inval = {0, 0, 0, 0};
- short j, shiftDelta;
- OSErr err;
-
- // quick sanity checks
- if (gTaskbarWindow == (WindowPtr)0L) return;
- if ((processArrayIndex < 0) || (processArrayIndex >= gPSNInfoItemsCount)) return;
-
- GetPort(&savedPort);
- SetPort(gTaskbarWindow);
-
- // determine the (graphical) shift in pixels
- shiftDelta = (gPSNInfoArray[processArrayIndex].buttonRect.right - gPSNInfoArray[processArrayIndex].buttonRect.left) + kTaskbarBetweenMargin;
-
- // deallocate any necessary memory
- err = DisposeIconSuite(gPSNInfoArray[processArrayIndex].iconSuite, TRUE);
-
- // invalidate the area to the right of the first shifted button
- inval = gPSNInfoArray[processArrayIndex].buttonRect;
- inval.right = gTaskbarWindow->portRect.right;
- InsetRect(&inval, -(kTaskbarButtonBorderSize), -(kTaskbarButtonBorderSize));
- InvalRect(&inval);
-
- // adjust the index for next
- gPSNInfoItemsCount--;
-
- // if we need to compact the array
- if (processArrayIndex < gPSNInfoItemsCount)
- {
- // we need to shift the remaining array elements up in the array (if necessary)
- BlockMoveData((Ptr)&gPSNInfoArray[processArrayIndex+1], (Ptr)&gPSNInfoArray[processArrayIndex], (gPSNInfoItemsCount - processArrayIndex) * sizeof(PSNRec));
-
- // adjust all the button rects to reflect the shift
- for (j = processArrayIndex; j < gPSNInfoItemsCount; j++)
- {
- gPSNInfoArray[j].buttonRect.left -= shiftDelta;
- gPSNInfoArray[j].buttonRect.right -= shiftDelta;
- }
- }
-
- // adjust the rect location for the next new process button
- gTaskbarNextPosition -= shiftDelta;
-
- // refresh display (if necessary)
- if (!EmptyRect(&inval))
- {
- savedClip = NewRgn();
- if (savedClip != (RgnHandle)0L)
- {
- GetClip(savedClip);
- ClipRect(&inval);
-
- DrawTaskbar(gTaskbarWindow);
-
- SetClip(savedClip);
- DisposeRgn(savedClip);
- }
- else
- {
- DrawTaskbar(gTaskbarWindow);
- }
- }
-
- SetPort(savedPort);
- }
-
-
- void RemovePSNFromProcessArray(ProcessSerialNumber *psn)
- {
- short i;
- OSErr err;
- Boolean result;
-
- for (i = 0; i < gPSNInfoItemsCount; i++)
- {
- err = SameProcess(psn, &gPSNInfoArray[i].psn, &result);
- if (result == TRUE)
- {
- Remove1TaskbarProcess(i);
- break;
- }
- }
- }
-
-
- Boolean FindPSNInProcessArray(ProcessSerialNumber *psn, short *processArrayIndex)
- {
- Boolean result = FALSE;
- short i;
- OSErr err;
-
- for (i = 0; i < gPSNInfoItemsCount; i++)
- {
- err = SameProcess(psn, &gPSNInfoArray[i].psn, &result);
- if (result == TRUE)
- {
- *processArrayIndex = i;
- break;
- }
- }
-
- return result;
- }
-
-
- Boolean FindPSNForClick(Point where, ProcessSerialNumber *psn, short *processArrayIndex)
- {
- Boolean result = FALSE;
- short i;
-
- for (i = 0; i < gPSNInfoItemsCount; i++)
- {
- if (PtInRect(where, &gPSNInfoArray[i].buttonRect))
- {
- *psn = gPSNInfoArray[i].psn;
- *processArrayIndex = i;
- result = TRUE;
- break;
- }
- }
-
- return result;
- }
-
-
- Boolean IsProcessAlive(ProcessSerialNumber *psn)
- {
- ProcessInfoRec psInfo;
-
- // get the process information
- psInfo.processInfoLength = sizeof(ProcessInfoRec);
- psInfo.processName = 0L; // I don't care about this
- psInfo.processAppSpec = 0L; // I don't care about this
-
- return (GetProcessInformation(psn, &psInfo) == noErr);
- }
-
-
- void UpdateProcessArray(void)
- {
- ProcessSerialNumber psn, frontPSN;
- RgnHandle savedClip;
- GrafPtr savedPort;
- Rect inval = {0, 0, 0, 0};
- short i, j, shiftDelta, index;
- OSErr err;
-
- // quick sanity check
- if (gTaskbarWindow == (WindowPtr)0L) return;
-
- GetPort(&savedPort);
- SetPort(gTaskbarWindow);
-
- // first, remove any processes that are no longer valid
- for (i = 0; i < gPSNInfoItemsCount; i++)
- {
- if (!IsProcessAlive(&(gPSNInfoArray[i].psn)))
- {
- // check to see if this is the currently hilited button rect
- if (EqualRect(&gCurrentlyHilitedButtonRect, &gPSNInfoArray[i].buttonRect))
- {
- gCurrentlyHilitedButtonRect.left = gCurrentlyHilitedButtonRect.right =
- gCurrentlyHilitedButtonRect.top = gCurrentlyHilitedButtonRect.bottom = 0;
- }
-
- // determine the (graphical) shift in pixels
- shiftDelta = (gPSNInfoArray[i].buttonRect.right - gPSNInfoArray[i].buttonRect.left) + kTaskbarBetweenMargin;
-
- // deallocate any necessary memory
- err = DisposeIconSuite(gPSNInfoArray[i].iconSuite, TRUE);
-
- // invalidate the area to the right of the first shifted button
- inval = gPSNInfoArray[i].buttonRect;
- inval.right = gTaskbarWindow->portRect.right;
- InsetRect(&inval, -(kTaskbarButtonBorderSize), -(kTaskbarButtonBorderSize));
- InvalRect(&inval);
-
- // adjust the index for next
- gPSNInfoItemsCount--;
-
- // if we need to compact the array
- if (i < gPSNInfoItemsCount)
- {
- // we need to shift the remaining array elements up in the array (if necessary)
- BlockMoveData((Ptr)&gPSNInfoArray[i+1], (Ptr)&gPSNInfoArray[i], (gPSNInfoItemsCount - i) * sizeof(PSNRec));
-
- // adjust all the button rects to reflect the shift
- for (j = i; j < gPSNInfoItemsCount; j++)
- {
- gPSNInfoArray[j].buttonRect.left -= shiftDelta;
- gPSNInfoArray[j].buttonRect.right -= shiftDelta;
- }
- }
-
- // adjust the rect location for the next new process button
- gTaskbarNextPosition -= shiftDelta;
- }
- }
-
- // refresh display (if necessary)
- if (!EmptyRect(&inval))
- {
- savedClip = NewRgn();
- if (savedClip != (RgnHandle)0L)
- {
- GetClip(savedClip);
- ClipRect(&inval);
-
- DrawTaskbar(gTaskbarWindow);
-
- SetClip(savedClip);
- DisposeRgn(savedClip);
- }
- else
- {
- DrawTaskbar(gTaskbarWindow);
- }
- }
-
- // loop over the processes looking for new processes to add
- psn.highLongOfPSN = psn.lowLongOfPSN = kNoProcess;
- do
- {
- err = GetNextProcess(&psn);
- if (err != noErr) break;
-
- if (!FindPSNInProcessArray(&psn, &index))
- AddProcessToTaskbar(&psn);
-
- } while (err == noErr);
-
- HiliteCurrentProcess();
- AdjustIcons();
-
- SetPort(savedPort);
- }
-
-
- void AdjustIcons(void)
- {
- short i;
-
- for (i = 0; i < gPSNInfoItemsCount; i++)
- {
- LayerPtr lp = ProcessLayer(&gPSNInfoArray[i].psn);
- Rect temp = gPSNInfoArray[i].buttonRect;
- OSErr err;
- Boolean processIsHidden;
-
- temp.right = temp.left + kStandardIconSize;
- processIsHidden = !HiddenLayer(lp);
- if (gPSNInfoArray[i].iconIsHilited == processIsHidden)
- err = PlotIconSuite(&temp, atLeft, processIsHidden ? ttDisabled : ttNone, gPSNInfoArray[i].iconSuite);
- }
- }
-
-
- void HiliteCurrentProcess(void)
- {
- ProcessSerialNumber frontPSN;
- short index;
- OSErr err;
-
- // make sure we have the front process framed correctly
- err = GetFrontProcess(&frontPSN);
- if (FindPSNInProcessArray(&frontPSN, &index))
- {
- if (!EqualRect(&gCurrentlyHilitedButtonRect, &gPSNInfoArray[index].buttonRect))
- {
- short i;
-
- gCurrentlyHilitedButtonRect = gPSNInfoArray[index].buttonRect;
-
- for (i = 0; i < gPSNInfoItemsCount; i++)
- Draw3DFrame(&gPSNInfoArray[i].buttonRect, (i == index) ? kFrameInset : kFrameOutset);
- }
- }
- else // the front process is ourselves, and we don't have a button
- {
- gCurrentlyHilitedButtonRect.left = gCurrentlyHilitedButtonRect.right =
- gCurrentlyHilitedButtonRect.top = gCurrentlyHilitedButtonRect.bottom = 0;
- }
- }
-
-
- void IdleTaskbar(void)
- {
- static const long kIdleThreshold = 20L;
-
- static GrafPtr savedPort = (GrafPtr)0L;
- static Point localPt = {0, 0};
- static Boolean overMyWindow = FALSE;
- static long ticks = 0L;
-
- if (LMGetTicks() >= (long)(ticks + kIdleThreshold))
- {
- // quick sanity check
- if (gTaskbarWindow == (WindowPtr)0L) return;
-
- // look where the mouse is, and roll up/down the taskbar if necessary
- GetPort(&savedPort);
- SetPort(gTaskbarWindow);
-
- GetMouse(&localPt);
- overMyWindow = PtInRect(localPt, &(gTaskbarWindow->portRect));
- if (overMyWindow && (gTaskbarVisible == FALSE))
- ToggleTaskbarVisibility(gTaskbarWindow);
- else if (!overMyWindow && (gTaskbarVisible == TRUE))
- ToggleTaskbarVisibility(gTaskbarWindow);
-
- SetPort(savedPort);
-
- UpdateProcessArray();
-
- ticks = LMGetTicks();
- }
- }
-
-
- void DoMacOSIconClick(EventRecord *theEvent)
- {
- MenuHandle myPopupMenuHandle = NULL;
- long mresult;
- short x = qd.screenBits.bounds.bottom - kTaskbarHeight;
- short y = qd.screenBits.bounds.left + 2;
- short lastItemSelected = 6;
-
- myPopupMenuHandle = GetMenu(150);
- if (myPopupMenuHandle)
- {
- InsertMenu( myPopupMenuHandle, hierMenu);
- mresult = PopUpMenuSelect(myPopupMenuHandle, x, y, lastItemSelected);
- DeleteMenu(150);
-
- if (HiWord(mresult) != 0) //something was selected
- {
- switch (LoWord(mresult))
- {
- case 1: // about
- // if (theEvent->modifiers & optionKey)
- // SendQuitToSelf();
- // else
- {
- ProcessSerialNumber curPSN, savedPSN;
- OSErr err;
-
- err = GetFrontProcess(&savedPSN);
- if (err != noErr) return;
-
- err = GetCurrentProcess(&curPSN);
- if (err != noErr) return;
-
- err = SetFrontProcess(&curPSN);
-
- // attempt to bring ourself front before proceeding
- PullApplicationToFront();
-
- Alert(128, 0);
-
- err = SetFrontProcess(&savedPSN);
- }
- break;
- case 3: // quit
- SendQuitToSelf();
- break;
- case 5: // restart
- SendRestartToFinder();
- break;
- case 6: // shutdown
- SendShutDownToFinder();
- break;
- }
- }
- ;
- }
-
-
- }
-
-
- Boolean TrackTaskbarButtonClick(EventRecord *theEvent, Rect *box)
- {
- // note, theEvent->where is already in local coordinates and the port is set up
-
- Point localPt;
- Boolean result = FALSE;
-
- if (StillDown())
- {
- Boolean inRect = TRUE;
-
- while (WaitMouseUp())
- {
- SystemTask();
- GetMouse(&localPt);
- if (PtInRect(localPt, box))
- {
- if (inRect == TRUE) continue;
-
- Draw3DFrame(box, kFrameInset);
-
- inRect = TRUE;
- }
- else
- {
- if (inRect == FALSE) continue;
-
- Draw3DFrame(box, kFrameOutset);
-
- inRect = FALSE;
- }
- }
-
- // now that the mouse has been released, set the real result
- GetMouse(&localPt);
- result = PtInRect(localPt, box);
-
- // fix up any left over drawing
- if ((result == FALSE) && (inRect == TRUE))
- {
- // we don't want to draw an outset frame if this button represents the current process
- ProcessSerialNumber frontPSN, psn;
- OSErr err;
- short index;
- if (FindPSNForClick(localPt, &psn, &index))
- {
- Boolean result;
- err = GetFrontProcess(&frontPSN);
- err = SameProcess(&frontPSN, &psn, &result);
- if (result != TRUE)
- Draw3DFrame(box, kFrameOutset);
- }
- else
- Draw3DFrame(box, kFrameOutset);
- }
- else if ((result == TRUE) && (inRect == FALSE))
- Draw3DFrame(box, kFrameInset);
- }
-
- return result;
- }
-
-
- void DoClickInTaskbar(EventRecord *theEvent, WindowPtr win)
- {
- ProcessSerialNumber psn;
- GrafPtr savePort;
- short index;
-
- GetPort(&savePort);
- SetPort(win);
-
- GlobalToLocal(&(theEvent->where));
- if (PtInRect(theEvent->where, &kMacOSIconRect))
- {
- DoMacOSIconClick(theEvent);
- }
- else if (FindPSNForClick(theEvent->where, &psn, &index))
- {
- if (TrackTaskbarButtonClick(theEvent, &(gPSNInfoArray[index].buttonRect)))
- {
- UpdateProcessArray();
-
- if (theEvent->modifiers & optionKey)
- TogglePSNVisibility(&psn);
- else if (theEvent->modifiers & cmdKey)
- {
- SendQuitToPSN(&psn);
- Remove1TaskbarProcess(index);
- }
- else
- BringPSNToFront(&psn);
- }
-
- HiliteCurrentProcess();
- AdjustIcons();
- }
-
- SetPort(savePort);
- }
-
-
- void AddProcessToTaskbar(ProcessSerialNumber *psn)
- {
- ProcessSerialNumber curPSN, frontPSN;
- ProcessInfoRec psInfo;
- FSSpec appSpec;
- Str31 appName;
- Rect r;
- OSErr err;
- short appNameWidth;
- FontInfo fInfo;
- Boolean result;
-
- // get the process information
- psInfo.processInfoLength = sizeof(ProcessInfoRec);
- psInfo.processName = appName;
- psInfo.processAppSpec = &appSpec;
- err = GetProcessInformation(psn, &psInfo);
- if (err != noErr)
- {
- // DebugStr("\pAddProcessToTaskbar- GetProcessInformation() failed;g");
- return;
- }
- else if (((psInfo.processType != 'APPL') && (psInfo.processType != 'FNDR')) ||
- (psInfo.processMode & modeOnlyBackground))
- return;
- else
- {
- err = GetCurrentProcess(&curPSN);
- err = SameProcess(&curPSN, psn, &result);
- if (result == TRUE)
- return;
- }
-
- // determine the width of the name
- TextSize(kTaskbarFontSize);
- TextFont(kTaskbarFont);
- TextFace(kTaskbarFontStyle);
- appNameWidth = StringWidth(appName);
- GetFontInfo(&fInfo);
-
- // determine this process' button's bounding box
- r.left = gTaskbarNextPosition;
- r.right = r.left + appNameWidth + (kTaskbarButtonBorderSize << 1) + 4 + kStandardIconSize;
- r.top = kTaskbarTopMargin;
- r.bottom = kTaskbarHeight - kTaskbarTopMargin;
-
- // bump up the next processes position
- gTaskbarNextPosition = r.right + kTaskbarBetweenMargin;
-
- // draw the frame (depends on being the front process or not)
- err = GetFrontProcess(&frontPSN);
- err = SameProcess(&frontPSN, psn, &result);
- Draw3DFrame(&r, (result == TRUE) ? kFrameInset : kFrameOutset);
-
- // remember this info in our process array
- gPSNInfoArray[gPSNInfoItemsCount].psn = *psn;
- gPSNInfoArray[gPSNInfoItemsCount].buttonRect = r;
- err = GetScriptableFinderFileIcon (&appSpec, FALSE, kAEWaitReply, &(gPSNInfoArray[gPSNInfoItemsCount].iconSuite));
-
- // draw the icon (thanks Leonard!)
- if (err == noErr)
- {
- LayerPtr lp = ProcessLayer(psn);
- Rect temp = r;
-
- temp.right = temp.left + kStandardIconSize;
-
- err = PlotIconSuite(&temp, atLeft, HiddenLayer(lp) ? ttNone : ttDisabled, gPSNInfoArray[gPSNInfoItemsCount].iconSuite);
- }
-
- // draw the text
- r.left += 4 + kStandardIconSize + 2;
- r.right -= 4;
- r.top = kTaskbarTopMargin + (((r.bottom - r.top) >> 1) - ((fInfo.ascent + fInfo.descent + fInfo.leading) >> 1));
- r.bottom = r.top + fInfo.ascent + fInfo.descent + fInfo.leading + 1;
- RGBBackColor(&kBgGrayColor);
- TETextBox((Ptr)(appName+1),(long)(*appName),&r,teJustCenter);
-
- // increment the array index (but avoid an overflow)
- gPSNInfoItemsCount++;
- if (gPSNInfoItemsCount > kMaxProcesses)
- gPSNInfoItemsCount = kMaxProcesses;
-
- }
-
-
- void DrawMacOSIcon()
- {
- GrafPtr savePort;
- Rect tempRect = kMacOSIconRect;
- OSErr err;
-
- // quick sanity check
- if (gTaskbarWindow == (WindowPtr)0L) return;
-
- // GetPort(&savePort);
- // SetPort(gTaskbarWindow);
-
- RGBBackColor(&kBgGrayColor);
- EraseRect(&tempRect);
-
- // draw the icon
- err = PlotIconID(&kMacOSIconRect, atNone, ttNone, kMacOSIconRsrcID);
-
- // draw the frame (3D coming out at you)
- Draw3DFrame(&kMacOSIconRect, kFrameOutset);
-
- BackColor(whiteColor);
-
- InsetRect(&tempRect, -(kTaskbarButtonFrameWidth), -(kTaskbarButtonFrameWidth)); // adjust for frame
- // ValidRect(&tempRect);
-
- // SetPort(savePort);
- }
-
-
- void Draw1TaskbarProcess(short processArrayIndex)
- {
- ProcessSerialNumber frontPSN;
- ProcessInfoRec psInfo;
- FSSpec appSpec;
- Str31 appName;
- Rect r, valid;
- OSErr err;
- short appNameWidth;
- FontInfo fInfo;
- Boolean result;
-
- if (processArrayIndex >= gPSNInfoItemsCount)
- {
- DebugStr("\pDraw1TaskbarProcess- illegal input param");
- return;
- }
-
- // get the process information
- psInfo.processInfoLength = sizeof(ProcessInfoRec);
- psInfo.processName = appName;
- psInfo.processAppSpec = &appSpec;
- err = GetProcessInformation(&(gPSNInfoArray[processArrayIndex].psn), &psInfo);
- if (err != noErr)
- {
- // DebugStr("\pDraw1TaskbarProcess- GetProcessInformation() failed;g");
- return;
- }
-
- // determine the width of the name
- TextSize(kTaskbarFontSize);
- TextFont(kTaskbarFont);
- TextFace(kTaskbarFontStyle);
- appNameWidth = StringWidth(appName);
- GetFontInfo(&fInfo);
-
- // determine this process' button's bounding box
- r.left = gTaskbarNextPosition;
- r.right = r.left + appNameWidth + (kTaskbarButtonBorderSize << 1) + 4 + kStandardIconSize;
- r.top = kTaskbarTopMargin;
- r.bottom = kTaskbarHeight - kTaskbarTopMargin;
-
- // bump up the next processes position
- gTaskbarNextPosition = r.right + kTaskbarBetweenMargin;
-
- // save a copy of the rect for later validation
- valid = r;
-
- // draw the frame (depends on being the front process or not)
- err = GetFrontProcess(&frontPSN);
- err = SameProcess(&frontPSN, &gPSNInfoArray[processArrayIndex].psn, &result);
- Draw3DFrame(&r, (result == TRUE) ? kFrameInset : kFrameOutset);
-
- // draw the icon (thanks Leonard!)
- if (err == noErr)
- {
- LayerPtr lp = ProcessLayer(&gPSNInfoArray[processArrayIndex].psn);
- Rect r2 = r;
-
- r2.right = r2.left + kStandardIconSize;
- err = PlotIconSuite(&r2, atLeft, HiddenLayer(lp) ? ttNone : ttDisabled, gPSNInfoArray[processArrayIndex].iconSuite);
- }
-
- // draw the text
- r.left += 4 + kStandardIconSize + 2;
- r.right -= 4;
- r.top = kTaskbarTopMargin + (((r.bottom - r.top) >> 1) - ((fInfo.ascent + fInfo.descent + fInfo.leading) >> 1));
- r.bottom = r.top + fInfo.ascent + fInfo.descent + fInfo.leading + 1;
- RGBBackColor(&kBgGrayColor);
- TETextBox((Ptr)(appName+1),(long)(*appName),&r,teJustCenter);
-
- // validate the drawing
- InsetRect(&valid, -(kTaskbarButtonFrameWidth), -(kTaskbarButtonFrameWidth)); // adjust for frame
- // ValidRect(&valid);
- }
-
-
- void DrawTaskbar(WindowPtr win)
- {
- GrafPtr savePort, workingPort;
- PixMapHandle pm;
- OSErr err;
- ProcessSerialNumber psn, myPSN;
- short i;
- Boolean buffering;
-
- GetPort(&savePort);
-
- // attempt to use offscreen buffering
- SetupOffscreenWorld();
- buffering = (gBufferWorld != (GWorldPtr)0L);
-
- if (buffering)
- {
- pm = GetGWorldPixMap(gBufferWorld);
- LockPixels(pm);
- SetPort((GrafPtr)gBufferWorld);
- workingPort = (GrafPtr)gBufferWorld;
- }
- else
- {
- SetPort(win);
- workingPort = (GrafPtr)win;
- }
-
-
- RGBBackColor(&kBgGrayColor);
- EraseRect(&workingPort->portRect);
-
- // draw the icon
- DrawMacOSIcon();
-
- // set the inital first position for locating the process buttons
- gTaskbarNextPosition = kTaskbarLeftMargin + kStandardIconSize + kTaskbarButtonBorderSize + kTaskbarBetweenMargin;
-
- for (i = 0; i < gPSNInfoItemsCount; i++)
- Draw1TaskbarProcess(i);
-
- BackColor(whiteColor);
- ForeColor(blackColor);
-
- // if we're using offscreen buffering, update the window here
- if (buffering)
- {
- UnlockPixels(pm);
- SetPort(win);
- UpdateFromOffscreenWorld(&workingPort->portRect);
- }
-
- // ValidRect(&win->portRect);
- SetPort(savePort);
- }
-
-
- // The following code was nabbed from MacApp
-
- void PullApplicationToFront()
- {
- EventRecord theEvent;
- short i;
-
- // The "Programmer's guide to MultiFinder says make an event call several times. I
- // guess 3 calls counts as several. Also, it says call GetNextEvent but we don't want
- // to lose events on the floor so we use EventAvail since it seems to work OK
- for (i = 1; i <= 3; ++i)
- EventAvail(everyEvent, &theEvent);
- } // PullApplicationToFront
-
- static Boolean IsThisKeyDown(const short theKey)
- {
- KeyMap km;
- Byte asBytes[16];
-
- GetKeys(km);
- BlockMove((Ptr)km, (Ptr)asBytes, 16);
- return (asBytes[theKey >> 3] & (1 << (theKey & 0x07))) ? TRUE : FALSE;
- } // IsThisKeyDown
-
- Boolean IsCommandKeyDown()
- {
- const short kCommandKey = 55;
- return IsThisKeyDown(kCommandKey);
- } // IsCommandKeyDown
-
- Boolean IsControlKeyDown()
- {
- const short kCtlKey = 0x3B;
- return IsThisKeyDown(kCtlKey);
- } // IsControlKeyDown
-
- Boolean IsOptionKeyDown()
- {
- const short kOptionKey = 58;
- return IsThisKeyDown(kOptionKey);
- } // IsOptionKeyDown
-
- Boolean IsShiftKeyDown()
- {
- const short kShiftKey = 56;
- return IsThisKeyDown(kShiftKey);
- } // IsShiftKeyDown
-
-
- // The following code was borrowed from DropShell 2.0 sources (thanks Leonard!)...
-
- /*** These routines use the Process Manager to give you information about yourself ***/
-
- void GetMyAppName(Str255 appName) {
- OSErr err;
- ProcessInfoRec info;
- ProcessSerialNumber curPSN;
-
- err = GetCurrentProcess(&curPSN);
-
- info.processInfoLength = sizeof(ProcessInfoRec); // ALWAYS USE sizeof!
- info.processName = appName; // so it returned somewhere
- info.processAppSpec = NULL; // I don't care!
-
- err = GetProcessInformation(&curPSN, &info);
- }
-
- void GetAppFSSpec(FSSpec *appSpec) {
- OSErr err;
- Str255 appName;
- ProcessInfoRec info;
- ProcessSerialNumber curPSN;
-
- err = GetCurrentProcess(&curPSN);
-
- info.processInfoLength = sizeof(ProcessInfoRec); // ALWAYS USE sizeof!
- info.processName = appName; // so it returned somewhere
- info.processAppSpec = appSpec; // so it can get returned!
-
- err = GetProcessInformation(&curPSN, &info);
- }
-
- /* ••• Apple event routines begin here ••• */
-
- /*
- This routine will create a targetDesc for sending to self.
-
- We take IM VI's advice and use the typePSN form with
- kCurrentProcess as the targetPSN.
- */
- OSErr GetTargetFromSelf (AEAddressDesc *targetDesc)
- {
- ProcessSerialNumber psn;
-
- psn.highLongOfPSN = 0;
- psn.lowLongOfPSN = kCurrentProcess;
-
- return( AECreateDesc(typeProcessSerialNumber, (Ptr)&psn, sizeof(ProcessSerialNumber), targetDesc) );
- }
-
- /* This routine will create a targetDesc using the apps signature */
- OSErr GetTargetFromSignature (OSType processSig, AEAddressDesc *targetDesc)
- {
- return( AECreateDesc(typeApplSignature, (Ptr)&processSig, sizeof(processSig), targetDesc) );
- }
-
-
- void SendQuitToSelf (void)
- {
- OSErr err;
- AEAddressDesc theTarget;
- AppleEvent quitAE, replyAE;
-
- /*
- First we create the target for the event. We call another
- utility routine for creating the target.
- */
- err = GetTargetFromSelf(&theTarget);
- if (err == noErr) {
- /* Next we create the Apple event that will later get sent. */
- err = AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, &theTarget, kAutoGenerateReturnID, kAnyTransactionID, &quitAE);
-
- if (err == noErr) {
- /*
- and finally send the event
- Since we are sending to ourselves, no need for reply.
- */
- err = AESend(&quitAE, &replyAE, kAENoReply + kAECanInteract, kAENormalPriority, 3600, NULL, NULL);
-
- /*
- NOTE: Since we are not requesting a reply, we do not need to
- need to dispose of the replyAE. It is there simply as a
- placeholder.
- */
- }
-
- /* and of course dispose of the quit AEVT itself */
- err = AEDisposeDesc(&quitAE);
- err = AEDisposeDesc(&theTarget);
- }
- }
-
-
- void SendQuitToPSN (ProcessSerialNumber *psn)
- {
- OSErr err;
- AEAddressDesc theTarget;
- AppleEvent quitAE;
-
- /*
- First we create the target for the event. We call another
- utility routine for creating the target.
- */
- err = AECreateDesc(typeProcessSerialNumber, psn, sizeof(ProcessSerialNumber), &theTarget);
- if (err == noErr) {
- /* Next we create the Apple event that will later get sent. */
- err = AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, &theTarget, kAutoGenerateReturnID, kAnyTransactionID, &quitAE);
-
- if (err == noErr) {
- /*
- and finally send the event
- Since we are sending to ourselves, no need for reply.
- */
- err = AESend(&quitAE, 0L, kAENoReply + kAECanInteract, kAENormalPriority, 3600, NULL, NULL);
-
- /*
- NOTE: Since we are not requesting a reply, we do not need to
- need to dispose of the replyAE. It is there simply as a
- placeholder.
- */
- }
-
- /* and of course dispose of the quit AEVT itself */
- err = AEDisposeDesc(&quitAE);
- err = AEDisposeDesc(&theTarget);
- }
- }
-
-
- void SendRestartToFinder()
- {
- OSErr err;
- OSType finderType = 'MACS';
- AEAddressDesc theTarget;
- AppleEvent restartAE;
-
- /*
- First we create the target for the event. We call another
- utility routine for creating the target.
- */
- err = AECreateDesc(typeApplSignature, &finderType, sizeof(OSType), &theTarget);
- if (err == noErr) {
- /* Next we create the Apple event that will later get sent. */
- err = AECreateAppleEvent('FNDR', 'rest', &theTarget, kAutoGenerateReturnID, kAnyTransactionID, &restartAE);
-
- if (err == noErr) {
- /*
- and finally send the event
- Since we are sending to ourselves, no need for reply.
- */
- err = AESend(&restartAE, 0L, kAENoReply + kAECanInteract, kAENormalPriority, 3600, NULL, NULL);
-
- /*
- NOTE: Since we are not requesting a reply, we do not need to
- need to dispose of the replyAE. It is there simply as a
- placeholder.
- */
- }
-
- /* and of course dispose of the quit AEVT itself */
- err = AEDisposeDesc(&restartAE);
- err = AEDisposeDesc(&theTarget);
- }
- }
-
-
- void SendShutDownToFinder()
- {
- OSErr err;
- OSType finderType = 'MACS';
- AEAddressDesc theTarget;
- AppleEvent shutDownAE;
-
- /*
- First we create the target for the event. We call another
- utility routine for creating the target.
- */
- err = AECreateDesc(typeApplSignature, &finderType, sizeof(OSType), &theTarget);
- if (err == noErr) {
- /* Next we create the Apple event that will later get sent. */
- err = AECreateAppleEvent('FNDR', 'shut', &theTarget, kAutoGenerateReturnID, kAnyTransactionID, &shutDownAE);
-
- if (err == noErr) {
- /*
- and finally send the event
- Since we are sending to ourselves, no need for reply.
- */
- err = AESend(&shutDownAE, 0L, kAENoReply + kAECanInteract, kAENormalPriority, 3600, NULL, NULL);
-
- /*
- NOTE: Since we are not requesting a reply, we do not need to
- need to dispose of the replyAE. It is there simply as a
- placeholder.
- */
- }
-
- /* and of course dispose of the quit AEVT itself */
- err = AEDisposeDesc(&shutDownAE);
- err = AEDisposeDesc(&theTarget);
- }
- }
-
-